<template>
	<view class="yb-overlay-box yb-flex" :style="{
		visibility: isShow ? 'visible' : 'hidden'
	}">
		<template v-if="maskSync.show">
			<view ref="ybOverlay" @tap="onClick" class="yb-overlay yb-flex" :class="overlayClass" :style="overlayStyle">
				<slot></slot>
			</view>
		</template>
		<template v-else>
			<view ref="ybOverlay" class="yb-overlay yb-overlay-none yb-flex" :class="overlayClass" :style="overlayStyle">
				<slot></slot>
			</view>
		</template>
	</view>
</template>

<script>
	import ComponentMixin from '../../js_sdk/componentMixin.js'
	import Util from '../../js_sdk/util.js'
	// #ifdef APP-NVUE
	const Binding = uni.requireNativePlugin('bindingx')
	// #endif
	export default {
		mixins: [ComponentMixin],
		props: {
			visible: {
				type: Boolean,
				default: false
			},
			duration: {
				type: Number,
				default: 300
			},
			options: {
				type: Object,
				default () {
					return new Object
				}
			}
		},
		computed: {
			optionsSync () {
				return Object.assign({}, {
					mask: true,
					position: 'fixed'
				}, this.options)
			},
			maskSync () {
				return Object.assign({}, {
					color: 'rgba(0,0,0,0.5)',
					show: true,
					click: true
				}, Util.typeof(this.optionsSync.mask) == 'Object' ? this.optionsSync.mask : Util.typeof(this.optionsSync.mask) == 'Boolean' ? {show: this.optionsSync.mask} : {})
			},
			overlayStyle () {
				return this.filterStyle(
					// #ifdef APP-NVUE
					Object.assign({}, {
						position: this.optionsSync.position,
						opacity: this.opacity
					}, this.maskSync.show ? { 'background-color': this.maskSync.color } : {})
					// #endif
					// #ifndef APP-NVUE
					Object.assign({}, {
						position: this.optionsSync.position,
						opacity: this.opacity,
						'animation-duration': this.duration + 'ms'
					}, this.maskSync.show ? { 'background-color': this.maskSync.color } : {})
					// #endif
				)
			}
		},
		data () {
			return {
				isShow: false,
				opacity: 0,
				overlay_binding: null,
				overlayClass: ''
			}
		},
		mounted() {
			this.isShow = this.visible
			this.$nextTick(function () {
				if ( this.isShow ) {
					this.show()
				}
			})
		},
		beforeDestroy() {
			this.reset()
		},
		methods: {
			show () {
				this.reset()
				// #ifdef APP-NVUE
				let mask = Util.getEl(this.$refs.ybOverlay);
				this.overlay_binding_show = Binding.bind({
				    eventType: 'timing',
					exitExpression: 't>' + this.duration,
				    props: [{
						element: mask,
						property: 'opacity',
						expression: `linear(t, 0, 1, ${this.duration})`
					}]
				}, (e) => {
					if ( e.state == 'exit' && e.t >= this.duration ) {
						if ( this.overlay_binding_show ) {
							Binding.unbind({
								token: this.overlay_binding_show.token,
								eventType: 'timing'
							})
							this.opacity = 1
							this.overlay_binding_show = null
							this.$emit('show')
							this.$emit('update:visible', true)
						}
					}
				})
				// #endif
				// #ifndef APP-NVUE
				this.overlayClass = 'yb-overlay-show'
				this.overlayTimer = setTimeout(() => {
					this.$emit('show')
					this.$emit('update:visible', true)
				}, this.duration)
				// #endif
			},
			hide () {
				this.reset()
				// #ifdef APP-NVUE
				let mask = Util.getEl(this.$refs.ybOverlay);
				this.overlay_binding_hide = Binding.bind({
				    eventType: 'timing',
					exitExpression: 't>' + this.duration,
				    props: [{
						element: mask,
						property: 'opacity',
						expression: `linear(t, 1, -1, ${this.duration})`
					}]
				}, (e) => {
					if ( e.state == 'exit' && e.t >= this.duration ) {
						if ( this.overlay_binding_hide ) {
							Binding.unbind({
								token: this.overlay_binding_hide.token,
								eventType: 'timing'
							})
							this.opacity = 0
							this.overlay_binding_hide = null
							this.$emit('hide')
							this.$emit('update:visible', false)
							this.isShow = false
						}
					}
				})
				// #endif
				// #ifndef APP-NVUE
				this.overlayClass = 'yb-overlay-hide'
				this.overlayTimer = setTimeout(() => {
					this.$emit('hide')
					this.$emit('update:visible', false)
					this.isShow = false
					this.overlayClass = ''
				}, this.duration)
				// #endif
			},
			reset () {
				// #ifdef APP-NVUE
				if ( this.overlay_binding_show ) {
					Binding.unbind({
						token: this.overlay_binding_show.token,
						eventType: 'timing'
					})
					this.overlay_binding_show = null
				}
				if ( this.overlay_binding_hide ) {
					Binding.unbind({
						token: this.overlay_binding_hide.token,
						eventType: 'timing'
					})
					this.overlay_binding_hide = null
				}
				// #endif
				// #ifndef APP-NVUE
				if ( this.overlayTimer ) {
					clearTimeout(this.overlayTimer)
					this.overlayTimer = null
				}
				// #endif
			},
			onClick () {
				if ( this.maskSync.click ) {
					this.hide()
				} 
			}
		},
		watch: {
			visible (newVal) {
				if ( newVal && !this.isShow ) {
					this.isShow = true
					this.$nextTick(function () {
						this.show()
					})
				} else if ( !newVal && this.isShow ) {
					this.hide()
				}
			}
		}
	}
</script>

<style scoped>
	/* #ifndef APP-NVUE */
	@keyframes opacity_show {
		from {
			opacity: 0;
		}
		to {
			opacity: 1;
		}
	}
	@keyframes opacity_hide {
		from {
			opacity: 1;
		}
		to {
			opacity: 0;
		}
	}
	/* #endif */
	/* #ifndef APP-NVUE */
	.yb-overlay-box {
		z-index: 9;
		pointer-events: none;
	}
	/* #endif */
	
	.yb-overlay {
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
	}
	
	/* #ifndef APP-NVUE */
	.yb-overlay-none {
		pointer-events: none;
	}
	.yb-overlay-show {
		animation-name: opacity_show;
		animation-fill-mode: forwards;
	}
	.yb-overlay-hide {
		animation-name: opacity_hide;
		animation-fill-mode: forwards;
	}
	/* #endif */
</style>